/** ****************************************************************************
@addtogroup RC_RX
@{
*******************************************************************************/

#include "rc_rx.h"

#define LOGTAG "RCRX"


/// 捕获状态复位
static void rc_capture_reset(driver_rcrx_t* dev) { 
	dev->min = MAXU16; 
	dev->max = 0; 
	dev->skipFrame = 0; 
	dev->pb->plen = 0; 
	dev->pb->next = 0;
}

/// 添加一个脉冲
/// @param filter 脉冲捕获过滤条件
/// @param rt 脉冲捕获运行时
/// @param pb 脉冲缓冲区
/// @param width 脉冲宽度(us)
/// @param level 脉冲电平。起始脉冲电平必须是低电平！
/// @return 是否满足基本条件，可以提交数据分析了
static bool rc_capture(driver_rcrx_t* dev, uint32_t width, uint8_t level) {
	do {
		if(dev->pb->plen == 0) {
			if(level != 0 || width < dev->LEAD_MIN || width > dev->WIDTH_MAX) {
				// 第一个脉冲，电平必须是低电平，宽度必须大于最小前导码脉宽
				//logchar('L');
				//logd("%c%d", level ? '+' : '-', width);
				break;
			}
			// 记录当前时间us(不算头部时间)
			dev->totalWidth = dev->lastUs;
		} else {
			if(level == dev->lastLevel) {
				// 电平没有变化，中间肯定是有丢失脉冲！
				// 极有可能是因为脉冲时间过短，中断还未返回，电平就变了！没有机会处理！
				//logchar('=');
				break;
			}
			if(dev->pb->plen >= CCODE_MAX_LEN) {
				// 缓冲区溢出！数据肯定有问题，清除重来！
				//logchar('>');
				break;
			}
		}

		if(width < dev->WIDTH_MIN) {
			// 遇到毛刺，重来
			//logchar('<');
			break;
		}
		if(width > dev->WIDTH_MAX && dev->pb->plen < CCODE_MIN_LEN) {
			// 脉冲宽度太宽，并且没有足够多的脉冲，则应清除重来
			//logchar('o');
			break;
		}

		if(dev->pb->plen == 2) {
			// 从第3个脉冲开始(跳过前导码)评估最大、最小差异度
			dev->max = dev->min = width;
		} 
		else if(dev->pb->plen > 2) {
			if(width >= dev->TAIL_MIN) {
				// 遇到一个结束码
				if(dev->pb->plen >= CCODE_MIN_LEN) {
					if(dev->skipFrame < dev->SKIP_FRAME) {
						// 如果没有达到要跳帧的数量，则先跳过，数据清空重来
						dev->skipFrame++;
						//logchar('x');
						break;
					}

					// ！！！当前编码长度够长，则提交分析！！！
					if(level == 0) {
						// 修正头尾的长度：如果头、尾电平相同，说明头尾相连，应该都除以2(或头尾相加除以4)
						width = (dev->pb->pulses[0] + width) >> 2;
						dev->pb->pulses[0] = width;
					}
					dev->pb->pulses[dev->pb->plen] = width; dev->pb->plen++;
					dev->lastLevel = level;
					// 计算总时间us(不算头和尾的时间)
					dev->totalWidth = osElapsedUs(dev->totalWidth) - width;
					return true;
				}

				// 当前编码长度不够，前面的所有数据无效清除，只保留当前的
				rc_capture_reset(dev);
				rc_capture(dev, width, level);
				return false;
			}

			// 刷新最大、最小值
			if(width > dev->max) {
				dev->max = width;
			} else if(width < dev->min) {
				dev->min = width;
			}

			if((dev->max >> 4) > dev->min) {
				// 如果除前导码外，最大的脉冲大于最小的脉冲的16倍，则前面的编码无效，重来
				//logchar('*');
				break;
			}
		}

		// 保存脉冲
		dev->pb->pulses[dev->pb->plen] = width; dev->pb->plen++;
		dev->lastLevel = level;	

		// 继续接收
		//logchar(level ? '+' : '-');
		return false;
	} while(0);

	// 重来
	//DBGREF(width); DBGREF(level);
	rc_capture_reset(dev);
	return false;
}

std_err_t rcrx_init(driver_rcrx_t* dev) {
	if(!dev || !dev->pb || !dev->extiEnable || !dev->extiDisable || !dev->getLevel) { return STD_ERR_INVALID_ARG; }
	dev->extiDisable();
	dev->state = RCRX_STATE_IDLE;
	// 捕获状态初始化
	rc_capture_reset(dev);
	return STD_ERR_OK;
}

void rcrx_start(driver_rcrx_t* dev, FUNC_RcRxCodeHandler codeHandler) {
	if(!dev || !codeHandler) { return; }
	
	// 先停止之前的
	dev->extiDisable();
	// 捕获状态初始化
	rc_capture_reset(dev);
	
	logd("RC-Rx start ...\r\n");
	dev->state = RCRX_STATE_SCAN;
	dev->lastUs = mcu_get_us();
	dev->codeHandler = codeHandler;
	dev->extiEnable(GPIO_INTR_NEGEDGE, 0);
}

void rcrx_stop(driver_rcrx_t* dev) {
	logd("RC-Rx stop.\r\n");
	rcrx_init(dev);
}

OSTaskDef(dpcRcDecode) {
	driver_rcrx_t* dev = getPointer(cookieData);
	RcCodecError err;
	bool _continue = false;
	
	do {	
		// 0.打印输出原始脉冲
		log("\r\n");
		uint32_t width = rc_pulse_buffer_get(dev->pb, 0);
		while(width) {
			log("%4d ", width);
			width = rc_pulse_buffer_next(dev->pb);
		}
		log("\r\nTotal: %d pulses, %d us.\r\n", dev->pb->plen, dev->totalWidth);
		
		// 1.0对脉冲缓冲区进行解析，并编码为脉冲索引码
		rc_pulse_index_code_t pic;
		uint8_t co;
		err = rc_pulse_index_code_parse(dev->pb, dev->totalWidth, dev->PWERR, &pic, &co);
		if(err) { break; }
		
		// 1.1打印输出脉冲索引码
		width = rc_pulse_index_code_get(&pic, 0);
		while(width) {
			log("%4d ", width);
			width = rc_pulse_index_code_next(&pic);
		}
		log("\r\n");
		
		// 2.0把脉冲索引码数据结构打包成数据流
		uint8_t *buf = (uint8_t*)dev->pb->pulses;
		uint16_t len = sizeof(dev->pb->pulses);
		err = rc_pulse_index_code_pack(&pic, buf, &len);
		if(err) { break; }
		
		// 2.1 调用应用层接收遥控码处理
		if(dev->codeHandler) { _continue = dev->codeHandler(buf, len); }
	} while(0);
	
	if(_continue) {
		// 捕获状态初始化，重新开始捕获
		rc_capture_reset(dev);
		dev->state = RCRX_STATE_SCAN;
	} else {
		// 停止捕获
		rcrx_stop(dev);
	}
}

OSTaskDef(dpcRcRecode) {
	driver_rcrx_t* dev = getPointer(cookieData);
	bool _continue = false;
	
	// 调用应用层接收遥控码处理
	if(dev->codeHandler) { _continue = dev->codeHandler((uint8_t*)dev->pb->pulses, dev->pb->plen * sizeof(dev->pb->pulses[0])); }
	
	if(_continue) {
		// 捕获状态初始化，重新开始捕获
		rc_capture_reset(dev);
		dev->state = RCRX_STATE_RECORD;
	} else {
		// 停止捕获
		rcrx_stop(dev);
	}
}

void rcrx_irqHandler(driver_rcrx_t* dev) {
	if(dev->state != RCRX_STATE_SCAN && dev->state != RCRX_STATE_RECORD) { return; }
	
	// 计算脉冲宽度，并重新计时
	uint32_t width = mcu_retiming_us(&dev->lastUs);
	// 取得前一个脉冲的电平(当前电平取反)
	uint8_t level = !dev->getLevel();
	
	// 捕获脉冲
	if(rc_capture(dev, width, level)) {
		if(dev->state == RCRX_STATE_SCAN) {
			// 开始解码任务
			osTaskRunLater(dpcRcDecode, sizeof(dev), &dev);
		} else if(dev->state == RCRX_STATE_RECORD) {
			// 开始应用层回调任务
			osTaskRunLater(dpcRcRecode, sizeof(dev), &dev);
		}
		// 设置为解码状态(避免再次捕获脉冲)
		dev->state = RCRX_STATE_ENCODE;
	}
}


/// @}
